﻿using System;
using System.Collections.Generic;

namespace Compiler.CompilerLogic
{
    [Serializable]
    public class Tetrade
    {
        public string Operation;
        public string FirstField;
        public string SecondField;
        public string ResultField;

        public Tetrade(string operation, string firstField, string secondField, string resultField)
        {
            Operation = operation;
            FirstField = firstField;
            SecondField = secondField;
            ResultField = resultField;
        }

        public override bool Equals(object obj)
        {
            return ((Tetrade)obj).Operation == Operation && ((Tetrade)obj).FirstField == FirstField &&
                   ((Tetrade)obj).SecondField == SecondField && ((Tetrade)obj).ResultField == ResultField;
        }
    }

    [Serializable]
    public class CodeGen
    {
        public List<Tetrade> TetradeList = new List<Tetrade>();
        public List<string> AssembleList = new List<string>();
        public int RCount = 1;
        public int MCount = 1;
        
        public Stack<int> Marks = new Stack<int>(); 
        private int level = 0;

        public void Go(SyntaxNode node,LexicalTables lex)
        { //Console.WriteLine(node.NodeName);
            switch (node.NodeName)
            {
                case "IfElseBlock":
                    break;
                case "If":
                    break;
                case "Else":
                    break;
                case "Assign":
                    break;
                case "Call":
                    TetradeList.Add(new Tetrade("CALL", "I" + lex.variableTable.FindIndex(x => x.Value == node.NodeVal &&
                                                    x.Level == 0), "", ""));
                    break;
                case "Procedure":
                    if (node.NodeVal != "main") level++;
                    else level = 0;
                    node.NodeVal = "I" + lex.variableTable.FindIndex(x => x.Value == node.NodeVal &&
                                                    x.Level == 0);
                    TetradeList.Add(new Tetrade("Proc", node.NodeVal, "", ""));
                    break;
                case "Block":
                    break;
                case "Expression":
                    break;
                case "While":
                    TetradeList.Add(new Tetrade("M"+MCount, "", "", ""));
                    MCount++;
                    break;
                case "Minus":
                    break;
                case "Ident":
                    if (level > 0)
                    {
                        if (lex.variableTable.Find(x => x.Value == node.NodeVal &&
                                                       (x.LUsed == 0 && x.Level == 1))!=null)
                        lex.variableTable.Find(x => x.Value == node.NodeVal &&
                                                    (x.LUsed == 0 && x.Level == 1)).LUsed = level;
                    node.NodeName = "I" + lex.variableTable.FindIndex(x => x.Value == node.NodeVal &&
                                                                        ((x.LUsed == level && x.Level == 1)||x.Level==0));
            }
                    else
            {
                node.NodeName = "I" + lex.variableTable.FindIndex(x => x.Value == node.NodeVal &&
                                                                        x.Level == 0);
            }
                break;
            case "Const":
                node.NodeName = "C" + lex.constantTable.FindIndex(x => x.Value == node.NodeVal);
                break;
            default:
                break;
        }

            foreach (SyntaxNode n in node.ChildNodes)
            {
                Go(n,lex);
            }

            switch (node.NodeName)
            {
                case "IfElseBlock":
                    break;
                case "If":
                        TetradeList.Add(new Tetrade("M" + MCount, "", "", ""));
                        MCount++;

                    break;
                case "Else":
                    break;
                case "Assign":
                    TetradeList.Add(new Tetrade("MOV", node.ChildNodes[1].NodeName, "", node.ChildNodes[0].NodeName));
                    break;
                case "Call":
                    break;
                case "Procedure":
                    break;
                case "Block":
                    if(node.ParentNode.NodeName=="Procedure")
                        if (node.ParentNode.NodeVal == "I"+(lex.variableTable.Count-1))
                        {
                            TetradeList.Add(new Tetrade("end", "", "", ""));
                        }
                        else
                        {
                            TetradeList.Add(new Tetrade("ret", "", "", ""));
                            TetradeList.Add(new Tetrade("endp", node.ParentNode.NodeVal, "", ""));
                        }
                    break;
                case "Expression":
                    if (node.NodeVal == "EQU" || node.NodeVal == "GTR" || node.NodeVal == "LSS")
                    {
                        if (node.ParentNode.NodeName == "Assign")
                        {
                            TetradeList.Add(new Tetrade("XOR", node.ChildNodes[0].NodeName, node.ChildNodes[0].NodeName, "R" + RCount));
                            RCount++;
                        }
                            TetradeList.Add(new Tetrade("CMP", node.ChildNodes[0].NodeName, node.ChildNodes[1].NodeName,
                                ""));
                            switch (node.NodeVal)
                            {
                                case "EQU":
                                    TetradeList.Add(new Tetrade("JNE", "M"+MCount, "", ""));
                                    break;
                                case "GTR":
                                    TetradeList.Add(new Tetrade("JNG", "M"+MCount, "", ""));
                                    break;
                                case "LSS":
                                    TetradeList.Add(new Tetrade("JNL", "M"+MCount, "", ""));
                                    break;
                            }
                        if (node.ParentNode.NodeName == "Assign")
                        {
                            TetradeList.Add(new Tetrade("NEG", "R"+(RCount-1), "","R"+(RCount-1)));
                            TetradeList.Add(new Tetrade("M"+MCount, "", "", "" ));
                            MCount++;
                            node.NodeName = "R" + RCount;
                            node.ChildNodes = null;
                            RCount++;
                        }

                        
                    }
                    else
                    {
                        TetradeList.Add(new Tetrade(node.NodeVal, node.ChildNodes[0].NodeName, node.ChildNodes[1].NodeName, "R"+RCount));
                        node.NodeName = "R" + RCount;
                        node.ChildNodes = null;
                        RCount++;
                    }
                    break;
                case "While":
                    TetradeList.Add(new Tetrade("JMP", "M"+(MCount-1), "", ""));
                    TetradeList.Add(new Tetrade("M"+MCount, "", "", ""));
                    MCount++;
                    break;
                case "Minus":
                    TetradeList.Add(new Tetrade("NEG", node.ChildNodes[0].NodeName, "", "R" + RCount));
                    node.NodeName = "R" + RCount;
                    node.ChildNodes = null;
                    RCount++;
                    break;
                default:
                    break;
            }

            node = node.ParentNode;
        }

        public CodeGen(LexicalTables lexTables)
        {
           Go(SyntaxTree.GetRoot(),lexTables);


            AssembleList.Add(".MODEL small");
            AssembleList.Add(".DATA");
            for (int i=0;i<=lexTables.variableTable.Count-1;i++)
            {
                if(lexTables.variableTable[i].Type!=0) AssembleList.Add("I" + i +" dw ?");
            }
            AssembleList.Add(".CONST");
            for (int i = 0; i <= lexTables.constantTable.Count - 1; i++)
            {
                if (lexTables.constantTable[i].Value != "true" || lexTables.constantTable[i].Value != "false") 
                    AssembleList.Add("C" + i + " dw "+ lexTables.constantTable[i].Value);
                else if (lexTables.constantTable[i].Value != "true")
                    AssembleList.Add("C" + i + " dw " + "1");
                else
                    AssembleList.Add("C" + i + " dw "+ "0");
            }
            AssembleList.Add(".CODE");
            foreach (Tetrade tetr in TetradeList)
            {
                AssembleList.Add(tetr.Operation + " ");
            }
        }
    }
}
